package com.meeting.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meeting.entity.MediaDeviceType;
import com.meeting.entity.MeetingRoom;
import com.meeting.entity.MeetingRoomDevice;
import com.meeting.entity.MeetingRoomStatus;
import com.meeting.exception.BusinessException;
import com.meeting.mapper.MediaDeviceTypeMapper;
import com.meeting.mapper.MeetingRoomDeviceMapper;
import com.meeting.mapper.MeetingRoomMapper;
import com.meeting.mapper.MeetingRoomStatusMapper;
import com.meeting.model.dto.bookingorder.BookingRequirementRequest;
import com.meeting.model.dto.meetingroom.MeetingRoomAddRequest;
import com.meeting.model.dto.meetingroom.MeetingRoomModifyRequest;
import com.meeting.model.dto.meetingroom.MeetingRoomQueryRequest;
import com.meeting.model.dto.meetingroom.MeetingRoomStatusModifyRequest;
import com.meeting.model.enums.MeetingRoomStatusEnum;
import com.meeting.model.vo.MeetingRoomAndDeviceList;
import com.meeting.model.vo.MeetingRoomAndStatusVO;
import com.meeting.model.vo.MeetingRoomRecommendVO;
import com.meeting.service.MeetingRoomService;
import com.meeting.utils.BitUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
* @author 25843
* @description 针对表【meeting_room(会议室表)】的数据库操作Service实现
* @createDate 2025-04-19 12:54:48
*/
@Service
public class MeetingRoomServiceImpl extends ServiceImpl<MeetingRoomMapper, MeetingRoom>
    implements MeetingRoomService{

    @Resource
    private MeetingRoomDeviceMapper meetingRoomDeviceMapper;

    @Resource
    private MeetingRoomMapper meetingRoomMapper;

    @Resource
    private MediaDeviceTypeMapper mediaDeviceTypeMapper;

    @Resource
    private BitUtil bitUtil;

    @Resource
    private MeetingRoomStatusMapper meetingRoomStatusMapper;

    /**
     * 新增会议室
     * @param meetingRoomAddRequest 新增会议室的请求体
     * @return Boolean
     */
    @Override
    public Boolean addMeetingRoom(MeetingRoomAddRequest meetingRoomAddRequest) {
        String name = meetingRoomAddRequest.getName();
        List<Integer> deviceList = meetingRoomAddRequest.getDeviceList();
        LambdaQueryWrapper<MeetingRoom> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MeetingRoom::getName, name);
        MeetingRoom one = this.getOne(queryWrapper);
        if (one != null) {
            throw new BusinessException(400, "会议室已存在");
        }
        MeetingRoom meetingRoom = new MeetingRoom();
        BeanUtils.copyProperties(meetingRoomAddRequest, meetingRoom);
        boolean b = this.save(meetingRoom);
        if (b) {
            MeetingRoom one1 = this.getOne(queryWrapper);
            List<MeetingRoomDevice> list = new ArrayList<>();
            for (Integer deviceId : deviceList) {
                MeetingRoomDevice meetingRoomDevice = new MeetingRoomDevice();
                meetingRoomDevice.setMeetingRoomId(one1.getId());
                meetingRoomDevice.setDeviceTypeId(deviceId);
                list.add(meetingRoomDevice);
            }
            meetingRoomDeviceMapper.insert(list);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 修改会议室
     * @param meetingRoomModifyRequest 修改会议室的请求体
     * @return Boolean
     */
    @Override
    public Boolean modifyMeetingRoom(MeetingRoomModifyRequest meetingRoomModifyRequest) {
        Long id = meetingRoomModifyRequest.getId();
        List<Integer> frontDeviceList = meetingRoomModifyRequest.getDeviceList();
        HashSet<Integer> frontDeviceSet = new HashSet<>(frontDeviceList);
        // 查询修改的会议室是否存在
        LambdaQueryWrapper<MeetingRoom> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MeetingRoom::getId, id);
        MeetingRoom one = this.getOne(queryWrapper);
        if (one == null) {
            throw new BusinessException(400, "会议室不存在");
        }
        // 修改会议室信息
        BeanUtils.copyProperties(meetingRoomModifyRequest, one);
        boolean b = this.updateById(one);
        // 修改会议室-设备信息
        if (b) {
            LambdaQueryWrapper<MeetingRoomDevice> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(MeetingRoomDevice::getMeetingRoomId, id);
            // 查出现在会议室有哪些设备
            List<MeetingRoomDevice> list = meetingRoomDeviceMapper.selectList(queryWrapper1);
            Set<Integer> collect = list.stream().map(MeetingRoomDevice::getDeviceTypeId).collect(Collectors.toSet());
            HashSet<Integer> backDeviceIdList = new HashSet<>(collect);
            // 没出现的就是要插入的
            List<MeetingRoomDevice> insertList = new ArrayList<>();
            for (Integer frontDeviceId : frontDeviceList) {
                if (!backDeviceIdList.contains(frontDeviceId)) {
                    MeetingRoomDevice meetingRoomDevice = new MeetingRoomDevice();
                    meetingRoomDevice.setMeetingRoomId(one.getId());
                    meetingRoomDevice.setDeviceTypeId(frontDeviceId);
                    insertList.add(meetingRoomDevice);
                }
            }
            // 没出现的就是要删除的
            List<Long> deleteList = list.stream()
                    .filter(o -> !frontDeviceSet.contains(o.getDeviceTypeId()))
                    .map(MeetingRoomDevice::getId).toList();
            if (!CollectionUtils.isEmpty(deleteList))
                meetingRoomDeviceMapper.deleteBatchIds(deleteList);
            if (!CollectionUtils.isEmpty(insertList))
                meetingRoomDeviceMapper.insert(insertList);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 删除会议室
     * @param meetingRoomId 删除的会议室id
     * @return Boolean
     */
    @Override
    @Transactional
    public Boolean deleteMeetingRoom(Long meetingRoomId) {
        LambdaQueryWrapper<MeetingRoom> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MeetingRoom::getId, meetingRoomId);
        MeetingRoom one = this.getOne(queryWrapper);
        if (one == null) {
            throw new BusinessException(400, "会议室不存在");
        }
        LambdaQueryWrapper<MeetingRoomStatus> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(MeetingRoomStatus::getMeetingRoomId, meetingRoomId);
        meetingRoomStatusMapper.delete(queryWrapper1);
        LambdaQueryWrapper<MeetingRoomDevice> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(MeetingRoomDevice::getMeetingRoomId, meetingRoomId);
        meetingRoomDeviceMapper.delete(queryWrapper2);
        return this.removeById(meetingRoomId);
    }

    /**
     * 根据查询条件获取查询包装器
     * @param queryRequest 查询条件
     * @return
     */
    @Override
    public Wrapper<MeetingRoom> getQueryWrapper(MeetingRoomQueryRequest queryRequest) {
        LambdaQueryWrapper<MeetingRoom> queryWrapper = new LambdaQueryWrapper<>();
        if (queryRequest == null) {
            return queryWrapper;
        }
        Long id = queryRequest.getId();
        String name = queryRequest.getName();
        Integer type = queryRequest.getType();
        Double area = queryRequest.getArea();
        Integer seatNum = queryRequest.getSeatNum();
        Double price = queryRequest.getPrice();

        queryWrapper.eq(ObjectUtils.isNotEmpty(id), MeetingRoom::getId, id);
        queryWrapper.like(StringUtils.isNotBlank(name), MeetingRoom::getName, name);
        queryWrapper.eq(ObjectUtils.isNotEmpty(type), MeetingRoom::getType, type);
        queryWrapper.eq(ObjectUtils.isNotEmpty(area), MeetingRoom::getArea, area);
        queryWrapper.eq(ObjectUtils.isNotEmpty(seatNum), MeetingRoom::getSeatNum, seatNum);
        queryWrapper.eq(ObjectUtils.isNotEmpty(price), MeetingRoom::getPrice, price);
        return queryWrapper;
    }

    /**
     * 分页查询会议室
     * @param page 分页信息
     * @param queryRequest 查询条件
     * @return Page<MeetingRoom>
     */
    @Override
    public Page<MeetingRoomAndStatusVO> queryMeetingRoom(Page<MeetingRoomAndDeviceList> page, MeetingRoomQueryRequest queryRequest) {
        List<Integer> deviceList = queryRequest.getDeviceList();
        int deviceListSize = 0;
        if (deviceList != null) {
            deviceListSize = deviceList.size();
        }
        Page<MeetingRoom> meetingRoomPage = this.baseMapper.queryMeetingRoom(page, queryRequest, deviceListSize);
        List<MeetingRoomAndStatusVO> list = meetingRoomPage.getRecords().stream().map(o -> {
            MeetingRoomAndStatusVO meetingRoomAndStatusVO = new MeetingRoomAndStatusVO();
            BeanUtils.copyProperties(o, meetingRoomAndStatusVO);
            meetingRoomAndStatusVO.setDate(queryRequest.getDate());
            LambdaQueryWrapper<MeetingRoomStatus> eq = new LambdaQueryWrapper<MeetingRoomStatus>().eq(MeetingRoomStatus::getMeetingRoomId, o.getId()).eq(MeetingRoomStatus::getDate, queryRequest.getDate());
            MeetingRoomStatus meetingRoomStatus = meetingRoomStatusMapper.selectOne(eq);
            if (meetingRoomStatus != null) {
                meetingRoomAndStatusVO.setStatus(meetingRoomStatus.getStatus());
            } else {
                String freeStatus = "4".repeat(8) + "0".repeat(13) + "4".repeat(3);
                meetingRoomAndStatusVO.setStatus(freeStatus);
                // 插入会议室状态
                MeetingRoomStatus meetingRoomStatus1 = new MeetingRoomStatus();
                meetingRoomStatus1.setMeetingRoomId(o.getId());
                meetingRoomStatus1.setDate(queryRequest.getDate());
                meetingRoomStatus1.setStatus(freeStatus);
                meetingRoomStatusMapper.insert(meetingRoomStatus1);
            }
            return meetingRoomAndStatusVO;
        }).toList();
        Page<MeetingRoomAndStatusVO> meetingRoomAndStatusVOPage = new Page<>();
        meetingRoomAndStatusVOPage.setRecords(list);
        meetingRoomAndStatusVOPage.setTotal(meetingRoomPage.getTotal());
        meetingRoomAndStatusVOPage.setPages(meetingRoomPage.getPages());
        meetingRoomAndStatusVOPage.setCurrent(meetingRoomPage.getCurrent());
        meetingRoomAndStatusVOPage.setSize(meetingRoomPage.getSize());
        return meetingRoomAndStatusVOPage;
    }

    @Override
    public Boolean modifyMeetingRoomStatus(MeetingRoomStatusModifyRequest request) {
        Long meetingRoomId = request.getMeetingRoomId();
        Date date = request.getDate();
        String status = request.getStatus();

        LambdaQueryWrapper<MeetingRoomStatus> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MeetingRoomStatus::getMeetingRoomId, meetingRoomId);
        queryWrapper.eq(MeetingRoomStatus::getDate, date);
        if (meetingRoomStatusMapper.selectOne(queryWrapper) == null) {
            MeetingRoomStatus meetingRoomStatus = new MeetingRoomStatus();
            meetingRoomStatus.setMeetingRoomId(meetingRoomId);
            meetingRoomStatus.setDate(date);
            meetingRoomStatus.setStatus(status);
            meetingRoomStatusMapper.insert(meetingRoomStatus);
            return true;
        } else {
            LambdaUpdateWrapper<MeetingRoomStatus> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(MeetingRoomStatus::getMeetingRoomId, meetingRoomId);
            updateWrapper.eq(MeetingRoomStatus::getDate, date);
            updateWrapper.set(MeetingRoomStatus::getStatus, status);
            return meetingRoomStatusMapper.update(updateWrapper) > 0;
        }
    }

    /**
     * 推荐会议室
     * @param requirementRequest 请求内容
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<MeetingRoomRecommendVO> recommendMeetingRooms(BookingRequirementRequest requirementRequest, long pageNum, long pageSize) {
        // 1. 验证时间参数
        Date startTime = requirementRequest.getStartTime();
        Date endTime = requirementRequest.getEndTime();
        Date now = new Date();

        if (startTime.before(now)) {
            throw new BusinessException(400, "开始时间不能早于当前时间");
        }

        if (endTime.before(startTime)) {
            throw new BusinessException(400, "结束时间不能早于开始时间");
        }

        // 检查预约日期是否在60天内
        Calendar maxBookingDate = Calendar.getInstance();
        maxBookingDate.setTime(now);
        maxBookingDate.add(Calendar.DAY_OF_YEAR, 60);
        if (startTime.after(maxBookingDate.getTime())) {
            throw new BusinessException(400, "预约日期不能超过60天");
        }

        // 检查预约时间是否在每日8:00到21:00之间
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startTime);
        int startHour = startCalendar.get(Calendar.HOUR_OF_DAY);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endTime);
        int endHour = endCalendar.get(Calendar.HOUR_OF_DAY);

        if (startHour < 8 || endHour > 21) {
            throw new BusinessException(400, "预约时间必须在每日8:00到21:00之间");
        }

        boolean isSameDay = startCalendar.get(Calendar.YEAR) == endCalendar.get(Calendar.YEAR)
                && startCalendar.get(Calendar.DAY_OF_YEAR) == endCalendar.get(Calendar.DAY_OF_YEAR);

        if (!isSameDay) {
            throw new BusinessException(400, "开始时间和结束时间不在同一天");
        }

        LambdaQueryWrapper<MeetingRoom> wrapper = new LambdaQueryWrapper<>();

        // 3. 根据座位数筛选
        Integer attendees = requirementRequest.getAttendees();
        if (attendees != null && attendees > 0) {
            wrapper.ge(MeetingRoom::getSeatNum, attendees);
        }

        // 4. 根据会议室类型筛选
        Integer roomType = requirementRequest.getRoomType();
        if (roomType != null) {
            wrapper.eq(MeetingRoom::getType, roomType);
        }

        // 5. 根据价格区间筛选
        Double maxPrice = requirementRequest.getMaxPrice();
        if (maxPrice != null && maxPrice > 0) {
            wrapper.le(MeetingRoom::getPrice, maxPrice);
        }

        // 6. 查询符合条件的会议室
        Page<MeetingRoom> meetingRoomPage = new Page<>(pageNum, pageSize);
        Page<MeetingRoom> roomPage = meetingRoomMapper.selectPage(meetingRoomPage, wrapper);

        // 7. 转换为VO对象
        Page<MeetingRoomRecommendVO> voPage = new Page<>(roomPage.getCurrent(), roomPage.getSize(), roomPage.getTotal());
        List<MeetingRoomRecommendVO> voList = new ArrayList<>();

        for (MeetingRoom room : roomPage.getRecords()) {
            // 查询会议室设备
            List<MediaDeviceType> deviceList = getDeviceListByRoomId(room.getId());
            List<Integer> deviceIds = deviceList.stream().map(MediaDeviceType::getId).toList();

            List<Integer> needDeviceIds =  requirementRequest.getDeviceIds();

            if (new HashSet<>(deviceIds).containsAll(needDeviceIds) && !bitUtil.isConflict(room.getId(), startTime, endTime)){
                // 创建推荐VO对象
                MeetingRoomRecommendVO vo = new MeetingRoomRecommendVO();
                BeanUtils.copyProperties(room, vo);
                vo.setDeviceList(deviceList);
                vo.setSeats(room.getSeatNum());
                vo.setPricePerHour(room.getPrice());
                vo.setStatus(bitUtil.getMeetingRoomTime(room.getId(), startTime));
                voList.add(vo);
            }
        }

        // 使用数据库查询结果的顺序
        voPage.setRecords(voList);
        voPage.setTotal(voList.size());
        return voPage;
    }

    /**
     * 获取会议室详情
     * @param meetingRoomId 会议室ID
     * @return 会议室详细信息
     */
    @Override
    public MeetingRoomRecommendVO getMeetingRoomDetail(Long meetingRoomId) {
        // 1. 查询会议室信息
        MeetingRoom meetingRoom = meetingRoomMapper.selectById(meetingRoomId);
        if (meetingRoom == null) {
            throw new BusinessException(404, "会议室不存在");
        }

        // 2. 转换为VO对象
        MeetingRoomRecommendVO vo = new MeetingRoomRecommendVO();
        BeanUtils.copyProperties(meetingRoom, vo);
        vo.setSeats(meetingRoom.getSeatNum());
        vo.setPricePerHour(meetingRoom.getPrice());

        // 3. 查询会议室设备
        List<MediaDeviceType> deviceList = getDeviceListByRoomId(meetingRoomId);
        vo.setDeviceList(deviceList);

        return vo;
    }

    @Override
    public String getMeetingRoomUsedTime(Long meetingRoomId, Date date) {
        String meetingRoomTime = bitUtil.getMeetingRoomTime(meetingRoomId, date);
        return meetingRoomTime;
    }

    /**
     * 获取会议室设备列表
     * @param roomId 会议室ID
     * @return 设备列表
     */
    private List<MediaDeviceType> getDeviceListByRoomId(Long roomId) {
        // 查询会议室设备关联
        LambdaQueryWrapper<MeetingRoomDevice> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.eq(MeetingRoomDevice::getMeetingRoomId, roomId);
        List<MeetingRoomDevice> roomDevices = meetingRoomDeviceMapper.selectList(deviceWrapper);

        if (CollectionUtils.isEmpty(roomDevices)) {
            return new ArrayList<>();
        }

        // 查询设备详情
        List<Integer> deviceTypeIds = roomDevices.stream()
                .map(MeetingRoomDevice::getDeviceTypeId)
                .collect(Collectors.toList());

        LambdaQueryWrapper<MediaDeviceType> typeWrapper = new LambdaQueryWrapper<>();
        typeWrapper.in(MediaDeviceType::getId, deviceTypeIds);

        return mediaDeviceTypeMapper.selectList(typeWrapper);
    }
}




